package network

import (
	"fmt"

	"github.com/pkg/errors"
)

var _ iNetworkManager = (*networkManager)(nil)

var (
	INetworkManager = new(networkManager)
	// Store 网络组件商店 string:网络组件类型id(mqtt);int64:网络组件id
	Store = make(map[string]map[int64]INetwork)
	// ProviderSupport 网络组件提供者 string:网络组件类型id
	ProviderSupport = make(map[string]INetworkProvider)
)

type (
	iNetworkManager interface {
		// GetNetwork 根据组件类型和ID获取网络组件
		GetNetwork(types *NetworkType, networkConfig *NetworkProperties, id int64) (INetwork, error)
		// GetNetworks 获取全部网络组件
		GetNetworks() []INetwork
		// GetProviders 获取全部网络组件提供商
		GetProviders() []INetworkProvider
		// GetProvider 根据类型获取提供商
		GetProvider(providerType string) INetworkProvider
		// Reload 重新加载网络组件
		Reload(types *NetworkType, networkConfig *NetworkProperties, id int64) error
		// Shutdown 停止网络组件
		Shutdown(types *NetworkType, id int64)
		// Destroy 销毁网络组件
		Destroy(types *NetworkType, id int64)
	}

	networkManager struct {
	}
)

func (n *networkManager) GetNetwork(types *NetworkType, networkConfig *NetworkProperties, id int64) (INetwork, error) {
	storeData := getNetworkStore(types)
	network := storeData[id]
	if network != nil {
		return network, nil
	}

	network, err := handleConfig(types, networkConfig, id, doCreate)
	if err != nil {
		return nil, err
	}
	storeData[id] = network

	return network, nil
}

func (n *networkManager) GetNetworks() []INetwork {
	var networkList []INetwork
	for _, v := range Store {
		for _, v1 := range v {
			networkList = append(networkList, v1)
		}
	}

	return networkList
}

func (n *networkManager) GetProviders() []INetworkProvider {
	var networkProvider []INetworkProvider
	for _, v := range ProviderSupport {
		networkProvider = append(networkProvider, v)
	}

	return networkProvider
}

func (n *networkManager) GetProvider(providerType string) INetworkProvider {
	return ProviderSupport[providerType]
}

func (n *networkManager) Reload(types *NetworkType, networkConfig *NetworkProperties, id int64) error {
	_, err := handleConfig(types, networkConfig, id, createOrUpdate)
	return err
}

func (n *networkManager) Shutdown(types *NetworkType, id int64) {
	storeData := getNetworkStore(types)
	network := storeData[id]
	if network == nil {
		return
	}

	network.Shutdown()
}

func (n *networkManager) Destroy(types *NetworkType, id int64) {
	storeData := getNetworkStore(types)
	network := storeData[id]
	if network == nil {
		return
	}

	// 如果存在则先停止然后删除
	n.Shutdown(types, id)
	delete(storeData, id)
}

// 根据提供者创建网络组件
func doCreate(provider INetworkProvider, _ int64, properties any) (INetwork, error) {
	network, err := provider.CreateNetwork(properties)
	if err != nil {
		return nil, err
	}

	return network, nil
}

// 创建或更新获取网络组建
func createOrUpdate(provider INetworkProvider, id int64, properties any) (INetwork, error) {
	storeData := getNetworkStore(provider.GetType())
	network := storeData[id]
	if network != nil {
		return provider.Reload(network, properties)
	}

	// 不存在
	network, err := provider.CreateNetwork(properties)
	if err != nil {
		return nil, err
	}
	storeData[id] = network

	return network, nil
}

// 创建网络组件
func handleConfig(types *NetworkType, networkConfig *NetworkProperties, id int64,
	fn func(INetworkProvider, int64, any) (INetwork, error)) (INetwork, error) {
	if _, ok := ProviderSupport[types.GetId()]; !ok {
		return nil, errors.New(fmt.Sprintf("创建网络组件失败：不支持的网络组件类型：%s，"+
			"Err：%+v", types.GetName(), nil))
	}

	// 根据类型和id获取配置信息
	if networkConfig == nil {
		return nil, errors.New(fmt.Sprintf("创建网络组件失败：网络组件类型：%s，配置ID：%d，不存在，"+
			"Err：%+v", types.GetName(), id, nil))
	}

	if !networkConfig.Enabled {
		return nil, errors.New(fmt.Sprintf("创建网络组件失败：网络组件类型：%s，配置ID：%d，已禁用，"+
			"Err：%+v", types.GetName(), id, nil))
	}

	provider := ProviderSupport[types.GetId()]
	createConfig, err := provider.CreateConfig(networkConfig)
	if err != nil {
		return nil, errors.New(fmt.Sprintf("创建网络组件失败：网络组件类型：%s，配置ID：%d，创建失败，"+
			"Err：%+v", types.GetName(), id, err))
	}

	// 创建或更新网络组件
	network, err := fn(provider, id, createConfig)
	if err != nil {
		return nil, err
	}

	return network, nil
}

// 根据类型获取网络组件数据map，如何无该类型数据，则创建一个该类型的空map数据
func getNetworkStore(types *NetworkType) map[int64]INetwork {
	id := types.GetId()
	if value, ok := Store[id]; ok {
		return value
	}

	// 不存在则创建并存入map
	Store[id] = make(map[int64]INetwork)

	return Store[id]
}

// Register 注册网络组建提供者
func Register(provider INetworkProvider) {
	ProviderSupport[provider.GetType().GetId()] = provider
}

// InitNetwork 初始化网络组件
func InitNetwork(networkConfigList []*NetworkProperties) {
	if len(networkConfigList) == 0 {
		return
	}

	for _, v := range networkConfigList {
		iNetworkType := new(NetworkType)
		networkType := iNetworkType.Of(v.Type)
		// reload网络组件
		err := INetworkManager.Reload(networkType, v, v.Id)
		if err != nil {
			continue
		}
	}
}

// CheckNetwork 定时检查网络组件
func CheckNetwork(networkConfigList []*NetworkProperties) {
	if len(Store) == 0 {
		return
	}

	// 处理网络组件数据
	networkConfigMap := make(map[int64]*NetworkProperties)
	for _, v := range networkConfigList {
		networkConfigMap[v.Id] = v
	}

	// 获取所有network集合
	var storeData []map[int64]INetwork
	for _, v := range Store {
		storeData = append(storeData, v)
	}

	// 获取所有network集合
	for k, v := range storeData {
		network := v[int64(k)]
		if network.IsAlive() {
			continue
		}

		provider := ProviderSupport[network.GetType().GetId()]
		networkConfig := networkConfigMap[int64(k)]
		if provider == nil || !network.IsAutoReload() || !networkConfig.Enabled {
			continue
		}

		// reload网络组件
		iNetworkType := new(NetworkType)
		networkType := iNetworkType.Of(network.GetType().GetId())
		err := INetworkManager.Reload(networkType, networkConfig, network.GetId())
		if err != nil {
			continue
		}
	}
}
